package com.openvid.webrtc.openvid;

import android.content.Context;
import android.os.AsyncTask;

import org.webrtc.ContextUtils;
import org.webrtc.HardwareVideoDecoderFactory;
import org.webrtc.HardwareVideoEncoderFactory;
import org.webrtc.PeerConnection;
import org.webrtc.PeerConnection.IceServer;
import org.webrtc.PeerConnectionFactory;
import org.webrtc.RtpTransceiver;
import org.webrtc.SoftwareVideoDecoderFactory;
import org.webrtc.SoftwareVideoEncoderFactory;
import org.webrtc.VideoDecoderFactory;
import org.webrtc.VideoEncoderFactory;
import org.webrtc.audio.AudioDeviceModule;
import org.webrtc.audio.JavaAudioDeviceModule;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;


public class Session {

    private String id;
    private String token;

    private final List<IceServer> iceServersDefault = Arrays.asList(IceServer.builder("stun:stun.l.google.com:19302").createIceServer());
    private List<IceServer> iceServers = new ArrayList();

    private PeerConnectionFactory peerConnectionFactory;
    private JavaAudioDeviceModule mAudioDeviceModule;
//    private RtcRoomDelegate mWebsocketDelegate;

    public Session(String id, String token, Context context) {
        this.id = id;
        this.token = token;
        // Creating a new PeerConnectionFactory instance
        PeerConnectionFactory.InitializationOptions.Builder optionsBuilder =
                PeerConnectionFactory.InitializationOptions.builder(context.getApplicationContext());
        optionsBuilder.setEnableInternalTracer(true);
        PeerConnectionFactory.InitializationOptions opt = optionsBuilder.createInitializationOptions();
        PeerConnectionFactory.initialize(opt);
        PeerConnectionFactory.Options options = new PeerConnectionFactory.Options();

        // Using software encoder and decoder
        final VideoEncoderFactory encoderFactory;
        final VideoDecoderFactory decoderFactory;

//        encoderFactory = new HardwareVideoEncoderFactory(null, false, false);
        encoderFactory = new SoftwareVideoEncoderFactory();
//        decoderFactory = new HardwareVideoDecoderFactory(null);
        decoderFactory = new SoftwareVideoDecoderFactory();



        mAudioDeviceModule=JavaAudioDeviceModule.builder(ContextUtils.getApplicationContext())
                .setInputSampleRate(16000)
                .createAudioDeviceModule();

        peerConnectionFactory = PeerConnectionFactory.builder()
                .setAudioDeviceModule(mAudioDeviceModule)
                .setVideoEncoderFactory(encoderFactory)
                .setVideoDecoderFactory(decoderFactory)
                .setOptions(options)
                .createPeerConnectionFactory();
    }

    public JavaAudioDeviceModule getAudioDeviceModule() {
        return mAudioDeviceModule;
    }

    //    public void setWebsocketDelegate(RtcRoomDelegate d) {
//        this.mWebsocketDelegate = d;
//    }

//    public void setWebSocket(CustomWebSocket websocket) {
//        this.websocket = websocket;
//    }

    public PeerConnection createLocalPeerConnection(IParticipant participant, PeerConnection.Observer observer) {
        do {
            if (iceServers.isEmpty()) {
                if (iceServerUri != null) {
                    IceServer.Builder iceServerBuilder;
                    try {
                        iceServerBuilder = IceServer.builder(iceServerUri);
                    } catch (IllegalArgumentException e) {
                        break;
                    }
                    if (iceServerUser != null) {
                        iceServerBuilder.setUsername(iceServerUser);
                    }
                    if (iceServerPass != null) {
                        iceServerBuilder.setPassword(iceServerPass);
                    }
                    iceServers.add(iceServerBuilder.createIceServer());
                }
            }
        } while (false);

        PeerConnection.RTCConfiguration config =
                new PeerConnection.RTCConfiguration(iceServers.isEmpty()
                        ? iceServersDefault
                        : iceServers);
        config.tcpCandidatePolicy = PeerConnection.TcpCandidatePolicy.ENABLED;
//        config.bundlePolicy = PeerConnection.BundlePolicy.MAXBUNDLE;
        config.bundlePolicy = PeerConnection.BundlePolicy.BALANCED;

        config.rtcpMuxPolicy = PeerConnection.RtcpMuxPolicy.NEGOTIATE;
        config.continualGatheringPolicy =
                PeerConnection.ContinualGatheringPolicy.GATHER_CONTINUALLY;
        config.keyType = PeerConnection.KeyType.ECDSA;
        config.enableDtlsSrtp = true;
        config.sdpSemantics = PeerConnection.SdpSemantics.UNIFIED_PLAN;

        PeerConnection peerConnection = peerConnectionFactory.createPeerConnection(config, observer);

        if (participant.getAudioTrack() != null) {
            peerConnection.addTransceiver(participant.getAudioTrack(),
                    new RtpTransceiver.RtpTransceiverInit(RtpTransceiver.RtpTransceiverDirection.SEND_ONLY));
        }
        if (participant.getVideoTrack() != null) {
            peerConnection.addTransceiver(participant.getVideoTrack(),
                    new RtpTransceiver.RtpTransceiverInit(RtpTransceiver.RtpTransceiverDirection.SEND_ONLY));
        }

        return peerConnection;
    }

//
////    private Set<Integer> mSets=new HashSet<>();
//    private void sendWhenIceCandidate(IceCandidate ic, String connectionId) {
//        CmdIceCandidate cmd=new CmdIceCandidate();
////        cmd.setCallback(respIceCandidate -> {
////            mSets.remove(cmd.getRequestId());
////        });
//        cmd.setParams(connectionId,ic.sdp,ic.sdpMid,ic.sdpMLineIndex);
//        mWebsocketDelegate.sendCmd(cmd);
////        int id=cmd.getRequestId();
////        mSets.add(id);
//    }


    public String getId() {
        return this.id;
    }

    public String getToken() {
        return this.token;
    }

    private String iceServerUri = null;
    private String iceServerUser = null;
    private String iceServerPass = null;

    public void setIceServerUri(String uri) {
        iceServerUri = uri;
    }

    public void setIceServerUser(String user) {
        iceServerUser = user;
    }

    public void setIceServerPass(String pass) {
        iceServerPass = pass;
    }

    public void setIceServers(List<IceServer> iceServers) {
        this.iceServers = iceServers;
    }

    public PeerConnectionFactory getPeerConnectionFactory() {
        return this.peerConnectionFactory;
    }

//    public void addRemoteParticipant(RemoteParticipant remoteParticipant) {
//        this.remoteParticipants.put(remoteParticipant.getConnectionId(), remoteParticipant);
//    }
//
//    public RemoteParticipant removeRemoteParticipant(String id) {
//        return this.remoteParticipants.remove(id);
//    }

    public void leaveSession() {
        AsyncTask.execute(() -> {
            if (peerConnectionFactory != null) {
                peerConnectionFactory.dispose();
                peerConnectionFactory = null;
            }
        });
    }
}
